<template>
  <div id="container" ref="containerRef" :style="scale"></div>

  <flow-node-dialog ref="flowNodeDialogRef" @update-node="handleUpdateNode"></flow-node-dialog>
  <flow-edge-dialog ref="flowEdgeDialogRef" @update-edge="handleUpdateEdge"></flow-edge-dialog>
</template>

<script setup lang="js">
import flow from "@/api/flow"
import {ElMessageBox} from 'element-plus'
import LogicFlow from "@logicflow/core";
import {DndPanel, SelectionSelect, Control, MiniMap, Menu, DynamicGroup} from '@logicflow/extension'

import "@logicflow/core/lib/style/index.css";
import '@logicflow/extension/lib/style/index.css';
import '@logicflow/extension/es/style/index.css'
import '@logicflow/extension/es/index.css';
import {computed, nextTick, onMounted, onUnmounted, ref} from "vue";

import CommonNode from "@/components/FlowContainer/nodes/CommonNode";
import ForNode from "@/components/FlowContainer/nodes/ForNode";
import IfNode from "@/components/FlowContainer/nodes/BooleanNode";
import IteratorNode from "@/components/FlowContainer/nodes/IteratorNode";
import MarkNode from "@/components/FlowContainer/nodes/MarkNode";
import SwitchNode from "@/components/FlowContainer/nodes/SwitchNode";
import WhileNode from "@/components/FlowContainer/nodes/WhileNode";
import FlowNodeDialog from "@/components/FlowContainer/nodeDialog.vue";
import FlowEdgeDialog from "@/components/FlowContainer/edgeDialog.vue";

const props = defineProps({
  height: {
    type: Number,
    default: 500
  },
  heightUnit: {
    type: String,
    default: "px"
  },
  parentContainerRef: {
    type: Object,
    default: () => {
      return null;
    }
  },
  renderData: {
    type: String,
    default: ""
  }
});
const containerRef = ref();
const instance = ref();
const containerHeight = ref(props.height);
const scale = computed(() => `width:100%; height: ${containerHeight.value}${props.heightUnit};`);
const selectionSelect = ref(false);
const flowNodeDialogRef = ref();
const flowEdgeDialogRef = ref();

const initPatternItems = () => {
  // 拖拽面板
  const patternItems = [
    {
      label: '一次选区',
      icon: '',
      callback: () => {
        instance.value.extension.selectionSelect.openSelectionSelect();
        instance.value.once('selection:selected', () => {
          instance.value.extension.selectionSelect.closeSelectionSelect();
        });
      }
    },
    {
      type: 'CommonNode',
      text: 'Common',
      label: 'Common 组件',
      icon: '',
      properties: {
        type: 'COMMON',
      }
    },
    {
      type: 'ForNode',
      text: 'For',
      label: 'For 组件',
      icon: '',
      properties: {
        type: 'FOR',
      },
    },
    {
      type: 'BooleanNode',
      text: 'Boolean',
      label: 'Boolean 组件',
      icon: '',
      properties: {
        type: 'BOOLEAN',
      }
    },
    {
      type: 'IteratorNode',
      text: 'Iterator',
      label: 'Iterator 组件',
      icon: '',
      properties: {
        type: 'ITERATOR',
      }
    },
    {
      type: 'MarkNode',
      text: ' ',
      label: 'Mark 组件',
      icon: '',
      properties: {
        type: 'MARK',
      }
    },
    {
      type: 'SwitchNode',
      text: 'Switch',
      label: 'Switch 组件',
      icon: '',
      properties: {
        type: 'SWITCH',
      }
    },
    {
      type: 'WhileNode',
      text: 'While',
      label: 'While 组件',
      icon: '',
      properties: {
        type: 'WHILE',
      }
    },
  ]
  instance.value.extension.dndPanel.setPatternItems(patternItems);
}

const initControlItems = () => {
  instance.value.extension.control.addItem({
    iconClass: 'icon-area',
    title: '',
    text: '持续选区',
    onClick: (thatLf, ev) => {
      if (selectionSelect.value) {
        instance.value.extension.selectionSelect.closeSelectionSelect();
      } else {
        instance.value.extension.selectionSelect.openSelectionSelect();
      }
      selectionSelect.value = !selectionSelect.value;
    }
  });
  instance.value.extension.control.addItem({
    iconClass: 'icon-clear',
    title: '',
    text: '清空画布',
    onClick: (thatLf, ev) => {
      thatLf.clearData();
    }
  });
  instance.value.extension.control.addItem({
    iconClass: 'icon-build',
    title: '',
    text: '构建',
    onClick: (thatLf, ev) => {
      console.log(JSON.stringify(thatLf.getGraphData()))
      buildEl(thatLf.getGraphData());
    }
  });
  instance.value.extension.control.addItem({
    iconClass: 'icon-run',
    title: '',
    text: '执行',
    onClick: (thatLf, ev) => {
      console.log(JSON.stringify(thatLf.getGraphData()))
      runEl(thatLf.getGraphData());
    }
  });
}

const initMenuItems = () => {
  // 为菜单追加选项
  instance.value.extension.menu.addMenuConfig({
    // 节点右键菜单
    nodeMenu: [
      {
        text: '属性',
        callback(node) {
          alert(`
          节点id：${node.id}
          节点类型：${node.type}
          节点坐标：(x: ${node.x}, y: ${node.y})`
          );
        },
      },
    ],
    // 边框右键菜单
    edgeMenu: [
      {
        text: '属性',
        callback(edge) {
          alert(`
          边id：${edge.id}
          边类型：${edge.type}
          边坐标：(x: ${edge.x}, y: ${edge.y})
          源节点id：${edge.sourceNodeId}
          目标节点id：${edge.targetNodeId}`
          );
        },
      },
    ],
    // 画布右键菜单
    graphMenu: [
      {
        text: '分享',
        callback() {
          alert('分享成功！');
        }
      },
    ],
  });
}

const initInstance = (data = null) => {
  instance.value = new LogicFlow({
    container: containerRef.value,
    grid: true,
    allowResize: true,
    allowRotate: true,
    enableNodeInGroupEdge: true,
    plugins: [DndPanel, SelectionSelect, Control, MiniMap, Menu, DynamicGroup],
    pluginsOptions: {
      miniMap: {
        width: 220,
        height: 220,
        showEdge: true,
        rightPosition: 10,
        bottomPosition: 10
      }
    }
  });
  // 注册自定义节点
  instance.value.register(CommonNode);
  instance.value.register(ForNode);
  instance.value.register(IfNode);
  instance.value.register(IteratorNode);
  instance.value.register(MarkNode);
  instance.value.register(SwitchNode);
  instance.value.register(WhileNode);
  initPatternItems();
  initControlItems();
  initMenuItems();
  initNodeClick();
  initEdgeClick();
  // 渲染数据
  if (data !== null && data !== '') {
    instance.value.render(JSON.parse(data));
  } else if (props.renderData !== null && props.renderData !== '') {
    instance.value.render(JSON.parse(props.renderData));
  }
  // 将图形移动到画布中央
  instance.value.translateCenter();
  // 开启小地图
  instance.value.extension.miniMap.show();
}

const initNodeClick = () => {
  instance.value.on('node:click', (node) => {
    if (node.data.type !== 'MarkNode') {
      flowNodeDialogRef.value.openDialog(node.data);
    } else {
      console.log(node.data.id)
    }
  });
}

const initEdgeClick = () => {
  instance.value.on('edge:click', (edge) => {
    // 来自哪个节点
    let sNode = instance.value.getNodeModelById(edge.data.sourceNodeId);
    // 去到哪个节点
    let tNode = instance.value.getNodeModelById(edge.data.targetNodeId);
    flowEdgeDialogRef.value.openDialog(sNode, tNode, edge.data);
  });
}

const handleResize = () => {
  if (props.parentContainerRef) {
    if (props.parentContainerRef.offsetHeight) {
      containerHeight.value = props.parentContainerRef.offsetHeight;
    }
  }
}

const handleUpdateNode = (nodeData) => {
  let nodeModelById = instance.value.getNodeModelById(nodeData.id);
  nodeModelById.text = nodeData.text;
  nodeModelById.setProperties(nodeData.properties);
}

const handleUpdateEdge = (edgeData) => {
  let edgeModelById = instance.value.getEdgeModelById(edgeData.id);
  edgeModelById.text.value = edgeData.properties.value;
  edgeModelById.setProperties(edgeData.properties);
}

onMounted(() => {
  window.addEventListener("resize", handleResize);
  nextTick(() => {
    // 初始化高度
    handleResize();
    // 初始化实例
    initInstance();
  });
});

onUnmounted(() => {
  window.removeEventListener("resize", handleResize);
});

const buildEl = (jsonObject) => {
  flow.buildEl.post(jsonObject).then(response => {
    console.log(response);
    ElMessageBox.confirm(response, '构建信息', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
    });
  });
}

const runEl = (jsonObject) => {
  flow.runEl.post(jsonObject).then(response => {
    ElMessageBox.confirm(response, '执行信息', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
    });
  });
}

const open = (data) => {
  if (instance.value) {
    instance.value.destroy();
  }
  initInstance(data);
}

defineExpose({open});
</script>

<style>
.icon-area {
  width: 16px;
  height: 16px;
  display: inline-block;
  /* 也可用 base64 */
  background-image: url('@/assets/area.svg');
  background-size: cover;
}

.icon-build {
  width: 16px;
  height: 16px;
  display: inline-block;
  background-image: url('@/assets/build.svg');
  background-size: cover;
}

.icon-clear {
  width: 16px;
  height: 16px;
  display: inline-block;
  background-image: url('@/assets/clear.svg');
  background-size: cover;
}

.icon-run {
  width: 16px;
  height: 16px;
  display: inline-block;
  background-image: url('@/assets/run.svg');
  background-size: cover;
}
</style>
